package com.zhangmeng.tools.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Utf8;
import com.zhangmeng.tools.music.SongInfo;
import com.zhangmeng.tools.music.kugou.KuGouMusic;
import com.zhangmeng.tools.music.kuwo.DownLoadInfo;
import com.zhangmeng.tools.music.kuwo.DownLoadURL;
import com.zhangmeng.tools.music.kuwo.SearchByKey;
import com.zhangmeng.tools.music.migu.MiGuMusic;
import com.zhangmeng.tools.music.migu.SwitchType;
import com.zhangmeng.tools.music.qianqian.QianQianMusic;
import com.zhangmeng.tools.music.qq.QQMusic;
import com.zhangmeng.tools.music.qq.QqEncrypt;
import com.zhangmeng.tools.music.qq.QqQuery;
import com.zhangmeng.tools.music.wangyiyun.Song;
import com.zhangmeng.tools.music.wangyiyun.WangYiYunMusic;
import com.zhangmeng.tools.utils.AlertUtils;
import com.zhangmeng.tools.utils.EncryptUtils;
import io.netty.util.internal.StringUtil;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.sql.Blob;
import java.util.*;

import static com.zhangmeng.tools.music.qq.RequestModule.apiServer;
import static com.zhangmeng.tools.music.qq.RequestModule.headerMap;

/**
 * @author : 芊芊墨客
 * @version : 1.0
 * @date : 2023-04-21 14:22
 */
@Slf4j
public class MusicDownloadController {

    @FXML
    public TableView<SongInfo> wangyiyun_music_table_view;

    @FXML
    public TableView<SongInfo> QQ_music_table_view;

    @FXML
    public TableView<SongInfo> kugou_music_table_view;

    @FXML
    public TableView<SongInfo> kuwo_music_table_view;

    @FXML
    public TableView<SongInfo> migu_music_table_view;

    @FXML
    public TableView<SongInfo> qianqian_music_table_view;

    public static double width = 350;

    @FXML
    public TabPane tabPane;

    @FXML
    public Button search;

    @FXML
    public TextField name;

    private static final SimpleIntegerProperty index = new SimpleIntegerProperty(0);

    public static final String ku_wo_vip_api = "http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?pn=1&rn=30&httpsStatus=1&reqId=a3d144b0-9570-11ed-9918-83c8c32b357d&key=";

    public static String download_url = "http://www.kuwo.cn/api/v1/www/music/playUrl?type=convert_url3&httpsStatus=1";

    public static SimpleObjectProperty<DownLoadInfo> down_load_info = new SimpleObjectProperty<>();
    public static SimpleObjectProperty<SearchByKey> data_bean = new SimpleObjectProperty<>();

    public static RestTemplate restTemplate;

    @FXML
    public Button downloading;


    @FXML
    public void initialize() {
        wangyiyun_music_init();
        qq_music_init();
        ku_gou_music_init();
        ku_wo_music_init();
        mi_gu_music_init();
        qianqian_music_init();

        tabPane.getSelectionModel().selectPrevious();//选择第一个选项卡

        tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
            @Override
            public void changed(ObservableValue<? extends Tab> observable, Tab oldValue, Tab newValue) {
                System.out.println(newValue.getText());
            }
        });

        tabPane.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                index.set(newValue.intValue());
            }
        });

        search.setOnAction(event -> {

            if (name.getText().length() == 0) {
                AlertUtils.alert_warning("请输入音乐名称!");
                return;
            }
            String title = name.getText();
            switch (index.get()) {
                case 0 -> set(wangyiyun_music_table_view, get_wangyiyun_song_info(title));
                case 1 -> set(QQ_music_table_view, get_qq_song_info(title));
                case 2 -> set(kugou_music_table_view, get_ku_gou_info(title));
                case 3 -> set(kuwo_music_table_view, get_kuwo_song_info(title));
                case 4 -> set(migu_music_table_view, get_migu_song_info(title));
                case 5 -> set(qianqian_music_table_view,get_qianqian_music_info(title));
            }
        });

        downloading.setOnAction(event -> {
            download_song();
        });
    }

    private ObservableList<SongInfo> get_qianqian_music_info(String title) {
        String api = "https://music.91q.com/v1/search?word=" + title+ "&pageNo=1&type=1&timestamp=1682223843&appid=16073360&sign=36fa85caedcd22f0f46ba834679537df";
        String json = HttpRequest.get(api).timeout(20000).execute().body();
        QianQianMusic qianQianMusic = JSON.parseObject(json, QianQianMusic.class);
        ObservableList<SongInfo> list = FXCollections.observableArrayList();
        List<QianQianMusic.DataBean.TypeTrackBean> results = qianQianMusic.getData().getTypeTrack();
        int id = 1;
        for (QianQianMusic.DataBean.TypeTrackBean resList : results) {
            SongInfo songInfo = new SongInfo();
            songInfo.setName(resList.getTitle());
            songInfo.setArtist(resList.getArtist().get(0).getName());
            songInfo.setAlbum(resList.getAlbumTitle());
            songInfo.setId(id);
            id++;
            list.add(songInfo);
        }
        return list;
    }

    public ObservableList<SongInfo> get_migu_song_info(String title) {

//        Map<String, Object> map = new HashMap<>();
//        map.put("song", 1);
//        String searchSwitch = map.toString();
//        String sid = (uuid() + uuid()).replace("-", "");
//        String url = "";
//        String target_url = "https://jadeite.migu.cn/music_search/v2/search/searchAll?sid=" + sid + "&isCorrect=1&isCopyright=1&searchSwitch=" + encode(searchSwitch) + "&pageSize=20&text=" + encode(title) + "&pageNo=1&feature=1000000000&sort=1";
//        String deviceId = EncryptUtils.md5(uuid().replace("-", "")).toUpperCase();
//        long timestamp = new Date().getTime();
//        String signature_md5 = "6cdc72a439cef99a3418d2a78aa28c73"; // app绛惧悕璇佷功鐨刴d5
//        String text = title + signature_md5 + "yyapp2d16148780a1dcc7408e06336b98cfd50" + deviceId + timestamp;
//        String sign = EncryptUtils.md5(text);
//
//        Map<String, Object> headers = new HashMap<>();
//        headers.put("appId", "yyapp2");
//        headers.put("uiVersion", "A_music_3.3.0");
//        headers.put("version", "7.0.4");
//        headers.put("deviceId", deviceId);
//        headers.put("sign", sign);
//        headers.put("timestamp", timestamp);
        SwitchType switchType = SwitchType.getSwitchType();
        Map<String, Object> map = new HashMap<>();
        map.put("feature","1111000000");
        map.put("isCopyright",1);
        map.put("isCorrect",1);
        map.put("pageIndex",1);
        map.put("pageSize",20);
        map.put("searchSwitch",JSON.toJSONString(switchType));
        map.put("sort",0);
        map.put("text",title);
        map.put("uiVersion","I_music_3.0.2");

        String target_url = "http://jadeite.migu.cn:7090/music_search/v2/search/searchAll";
        String json = HttpRequest.get(target_url)
                .form(map).timeout(20000).execute().body();

        MiGuMusic miGuMusic = JSON.parseObject(json, MiGuMusic.class);
        ObservableList<SongInfo> list = FXCollections.observableArrayList();
        List<MiGuMusic.Result> results = miGuMusic.getSongResultData().getResult();
        int id = 1;
        for (MiGuMusic.Result resList : results) {
            SongInfo songInfo = new SongInfo();
            songInfo.setName(resList.getSongName());
            songInfo.setArtist(resList.getSinger());
            songInfo.setAlbum(resList.getAlbum());
            songInfo.setId(id);
            id++;
            list.add(songInfo);
        }
        return list;
    }

    public String uuid() {
        return UUID.randomUUID().toString();
    }

    public String encode(String url) {
        return java.net.URLEncoder.encode(url, StandardCharsets.UTF_8);
    }

    public ObservableList<SongInfo> get_ku_gou_info(String title) {
        String api = "https://songsearch.kugou.com/song_search_v2";
        ObservableList<SongInfo> list = FXCollections.observableArrayList();
        HashMap<String, Object> paramMap = new HashMap<>();
        paramMap.put("keyword", title);
        paramMap.put("page", 1);

        String result3 = HttpUtil.get(api, paramMap);
        KuGouMusic kuGouMusic = JSON.parseObject(result3, KuGouMusic.class);
        if (kuGouMusic.getData() != null) {
            List<KuGouMusic.ResList> lists = kuGouMusic.getData().getLists();
            int id = 1;
            for (KuGouMusic.ResList resList : lists) {
                SongInfo songInfo = new SongInfo();
                songInfo.setName(resList.getSongName());
                songInfo.setArtist(resList.getSingerName());
                songInfo.setAlbum(resList.getAlbumName());
                songInfo.setId(id);
                id++;
                list.add(songInfo);
            }
        }
        return list;
    }

    public ObservableList<SongInfo> get_kuwo_song_info(String title) {
        ObservableList<SongInfo> list = FXCollections.observableArrayList();
        List<SongInfo> lists = request_api(title);
        int i = 0;
        for (SongInfo listBean : lists) {
            i = i + 1;
            listBean.setId(i);
            list.add(listBean);
        }

        return list;
//        inputStream = response.getEntity().getContent();
//        byte[] buffer = new byte[1024];
//        int readBytes = 0;
//        StringBuilder stringBuilder = new StringBuilder();
//        while((readBytes = inputStream.read(buffer)) > 0){
//            Thread.sleep(1);
//            stringBuilder.append(new String(buffer, 0, readBytes));
//        }
    }

    public static List<SongInfo> request_api(String key) {
        String headers_json_path = MusicDownloadController.class.getClassLoader().getResource("headers.json").toExternalForm();
        try {
            List<String> list = FileUtil.readLines(new URL(headers_json_path), StandardCharsets.UTF_8);
            StringBuilder stringBuilder = new StringBuilder();
            list.forEach(stringBuilder::append);
            String headers_json = stringBuilder.toString();
            Map<String, String> map = JSONObject.parseObject(headers_json, Map.class);

            MultiValueMap<String, String> headers = new HttpHeaders();
            for (Map.Entry<String, String> entry : map.entrySet()) {
                headers.add(entry.getKey(), entry.getValue());
            }
            HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(headers);

            if (restTemplate == null) {
                restTemplate = new RestTemplate();
            }
            SearchByKey result = restTemplate.exchange(ku_wo_vip_api + key, HttpMethod.GET, httpEntity, SearchByKey.class).getBody();
            if (result != null) {
                data_bean.setValue(result);
                return result.getData().getList();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return null;
    }


    public ObservableList<SongInfo> get_qq_song_info(String title) {
        ObservableList<SongInfo> list = FXCollections.observableArrayList();
        //String api = "https://u.y.qq.com/cgi-bin/musicu.fcg";
        QqQuery query = new QqQuery();
        QqQuery.Comm comm = new QqQuery.Comm("19", "1859", "0");
        query.setComm(comm);

        QqQuery.Req req = new QqQuery.Req();
        req.setMethod("DoSearchForQQMusicDesktop");
        req.setModule("music.search.SearchCgiService");
        QqQuery.Req.Param param = new QqQuery.Req.Param();
        param.setGrp(1);
        param.setNumPerPage(50);
        param.setPageNum(1);
        param.setQuery(title);
        param.setSearchType(0);
        req.setParam(param);
        query.setReq(req);
        String q = JSON.toJSONString(query);
        Random ran = new Random(System.currentTimeMillis());
        String result2 = HttpRequest.post(apiServer[ran.nextInt(apiServer.length)])
                .header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66")
                .header("accept-encoding", "application/json")
                .form("sign", getSign(q))//表单内容
                .body(q)
                .timeout(20000)//超时，毫秒
                .execute().body();
        QQMusic qqMusic = JSON.parseObject(result2, QQMusic.class);
        if (qqMusic.getReq() != null) {
            QQMusic.ResData data = qqMusic.getReq().getData();
            QQMusic.Song song = data.getBody().getSong();
            List<QQMusic.ResList> list1 = song.getList();
            if (list1.size() > 0) {
                int id = 1;
                for (QQMusic.ResList resList : list1) {
                    SongInfo songInfo = new SongInfo();
                    songInfo.setName(resList.getName());
                    songInfo.setArtist(resList.getSinger().get(0).getName());
                    songInfo.setAlbum(resList.getAlbum().getName());
                    songInfo.setId(id);
                    id++;
                    list.add(songInfo);
                }
            }
        }
        return list;
    }

    public String getSign(String params) {
        return QqEncrypt.getSign(JSON.toJSONString(params));
    }

    public ObservableList<SongInfo> get_wangyiyun_song_info(String title) {
        ObservableList<SongInfo> list = FXCollections.observableArrayList();
        String api = "https://music.163.com/api/search/pc";
        Map<String, Object> query = new HashMap<>();
        query.put("s", title);
        query.put("offset", 0);
        query.put("limit", 30);
        query.put("type", 1);

        String result2 = HttpRequest.post(api)
                .header(Header.USER_AGENT, "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36")//头信息，多个头信息多次调用此方法即可
                .form(query)//表单内容
                .timeout(20000)//超时，毫秒
                .execute().body();
        WangYiYunMusic wangYiYunMusic = JSON.parseObject(result2, WangYiYunMusic.class);
        if (wangYiYunMusic.getResult() == null) {
            result2 = HttpRequest.post(api)
                    .header(Header.USER_AGENT, "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36")//头信息，多个头信息多次调用此方法即可
                    .form(query)//表单内容
                    .timeout(20000)//超时，毫秒
                    .execute().body();
        }
        wangYiYunMusic = JSON.parseObject(result2, WangYiYunMusic.class);
        List<Song> songs = wangYiYunMusic.getResult().getSongs();
        if (songs.size() > 0) {
            int id = 1;
            for (Song song : songs) {
                SongInfo songInfo = new SongInfo();
                songInfo.setName(song.getName());
                songInfo.setArtist(song.getArtists().get(0).getName());
                songInfo.setAlbum(song.getAlbum().getName());
                songInfo.setId(id);
                songInfo.setMp3Url(song.getMp3Url());
                list.add(songInfo);
                id++;
            }
        }

        return list;
    }


    public static void set_songInfo(SongInfo listBean) {
        String url = null;
        //判断音乐类型
        switch (index.get()){
            case 0://网易云
                url = listBean.getMp3Url();
                break;
            case 3://酷我
                String req_id = data_bean.getValue().getReqId();
                int mid = listBean.getRid();
                url = download_url + "&reqId=" + req_id + "&mid=" + mid;
                break;
        }

        if (restTemplate == null) {
            restTemplate = new RestTemplate();
        }
        DownLoadURL result = restTemplate.getForObject(url, DownLoadURL.class);
        if (result != null) {
            String url1 = result.getData().getUrl();
            DownLoadInfo loadInfo = new DownLoadInfo();
            loadInfo.setSong_url(url1);
            loadInfo.setSong_name(listBean.getName());
            loadInfo.setSong_author(listBean.getArtist());
            down_load_info.set(loadInfo);
        }
    }

    public static void download_song(){
        String path = "C:/Users/Administrator/Desktop/";
        DownLoadInfo value = down_load_info.getValue();
        if (value != null){
            String song_name =value.getSong_author() + "--" +  value.getSong_name() + ".mp3";
            String save_path = path + song_name;
            save_file(save_path,value.getSong_url());
        }
    }
    public static void save_file(String save_path,String download_url){
        try {
            Path path1 = Paths.get(save_path);

            File file = path1.toFile();
            if (!file.exists()){
                file.createNewFile();
            }
            boolean exists = Files.exists(path1);
            if (!exists){
                Files.createFile(path1);
            }

            FileOutputStream fs = new FileOutputStream(file);
            URL url = new URL(download_url);
            InputStream inputStream = url.openStream();
            int available = inputStream.available();
            byte[] bytes = new byte[1024];
            int byteRead = 0;
            while ((byteRead = inputStream.read(bytes)) != -1 ){
                fs.write(bytes, 0, byteRead);
            }
            inputStream.close();
            fs.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public void set(TableView<SongInfo> tableView, ObservableList<SongInfo> items) {
        tableView.setItems(items);
    }

    public void wangyiyun_music_init() {
        init(wangyiyun_music_table_view);
    }

    public void qq_music_init() {
        init(QQ_music_table_view);
    }

    public void ku_gou_music_init() {
        init(kugou_music_table_view);
    }

    public void ku_wo_music_init() {
        init(kuwo_music_table_view);
    }

    public void mi_gu_music_init() {
        init(migu_music_table_view);
    }

    public void qianqian_music_init() {
        init(qianqian_music_table_view);
    }

    public void init(TableView<SongInfo> init_table) {
        init_table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        init_table.getSelectionModel().select(0);

        TableColumn<SongInfo, String> user_name = new TableColumn<>("歌手名");
        user_name.setCellValueFactory(new PropertyValueFactory<SongInfo, String>("artist"));

        TableColumn<SongInfo, String> song_name = new TableColumn<>("歌曲名");
        song_name.setCellValueFactory(new PropertyValueFactory<SongInfo, String>("name"));

        TableColumn<SongInfo, String> zhuan_ji_name = new TableColumn<>("专辑");
        zhuan_ji_name.setCellValueFactory(new PropertyValueFactory<SongInfo, String>("album"));

        TableColumn<SongInfo, String> id = new TableColumn<>("序号");
        id.setCellValueFactory(new PropertyValueFactory<SongInfo, String>("id"));

        user_name.setPrefWidth(width);
        song_name.setPrefWidth(width);
        zhuan_ji_name.setPrefWidth(width);
        id.setPrefWidth(width);

        init_table.getColumns().add(id);
        init_table.getColumns().add(song_name);
        init_table.getColumns().add(user_name);
        init_table.getColumns().add(zhuan_ji_name);

        init_table.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null){
                set_songInfo(newValue);
            }
        });
    }
}
